home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swagd_f.zip / EGAVGA.SWG / 0157_FLI Player.pas < prev    next >
Pascal/Delphi Source File  |  1995-03-03  |  14KB  |  398 lines

  1. {
  2. > Where can I get TP7 or TP6 source code for playing back FLI animations? If
  3. > there aren't any, is there an efficient, quick, and unnoticeable way to do
  4. > a shell to DOS and run a FLI player program? Any and all help is greatly
  5. > appreciated. Please, if possible, email to the address in my .sig below.
  6.  
  7. Here is my the unit I use to play FLI files.  Hope it Helps.
  8. From: JOHARROW@homeloan.demon.co.uk (John O'Harrow)
  9. }
  10.  
  11. {----------Written by John O'Harrow 1994----------}
  12.  
  13. {$G+}
  14. UNIT FliPlay;
  15.  
  16. INTERFACE
  17.  
  18.   PROCEDURE AAPlay(Filename : String); {Play FLI at default speed}
  19.  
  20. TYPE
  21.   PFliPlayer = ^TFliPlayer;
  22.   TFliPlayer = OBJECT
  23.     CONSTRUCTOR Init;
  24.     DESTRUCTOR  Done;                      VIRTUAL;
  25.     PROCEDURE   SetSpeed(Speed : Integer); VIRTUAL; {0=Fastest}
  26.     PROCEDURE   ClearSpeed;                VIRTUAL;
  27.     PROCEDURE   Play(Filename : String);   VIRTUAL;
  28.   PRIVATE
  29.     Buffer   : Pointer;
  30.     Interval : Integer;
  31.     FliFile  : File;
  32.   END; {TFliPlayer}
  33.  
  34. IMPLEMENTATION
  35.  
  36. USES
  37.   Crt;
  38.  
  39. CONST
  40.   Clock_Hz     = 4608;                   {Frequency of clock}
  41.   Monitor_Hz   = 70;                     {Frequency of monitor}
  42.   Clock_Scale  = Clock_Hz DIV Monitor_Hz;
  43.   CData        = $40;                    {Port number of timer 0}
  44.   CMode        = $43;                    {Port number of timer control word}
  45.   BufSize      = 65528;                  {Frame buffer size - Must be even}
  46.   MCGA         = $13;                    {Number for MCGA mode}
  47.  
  48. TYPE
  49.   MainHeaderRec = RECORD
  50.     Padding1 : LongInt;
  51.     ID       : Word;
  52.     Frames   : Word;
  53.     Padding2 : LongInt;
  54.     Padding3 : LongInt;
  55.     Speed    : Word;
  56.     Padding4 : ARRAY[1..110] OF Char; {Pad to 128 Bytes}
  57.   END; {MainHeaderRec}
  58.  
  59.   FrameHeaderRec = RECORD
  60.     Size     : LongInt;
  61.     Padding1 : Word;
  62.     Chunks   : Word;
  63.     Padding2 : ARRAY[1..8] OF Char; {Pad to 16 Bytes}
  64.   END; {FrameHeaderRec}
  65.  
  66. {---------------------------------------------------------------------------}
  67.  
  68.   PROCEDURE VideoMode(Mode : Word);
  69.     INLINE ($58/$CD/$10); {POP AX/INT 10}
  70.  
  71.   PROCEDURE InitClock; ASSEMBLER; {Taken from the FLILIB source}
  72.   ASM
  73.     mov  al,00110100b
  74.     out  CMode,al
  75.     xor  al,al
  76.     out  CData,al
  77.     out  CData,al
  78.   END; {InitClock}
  79.  
  80.   FUNCTION GetClock : LongInt; ASSEMBLER; {Taken from the FLILIB source}
  81.   {this routine returns a clock with occassional spikes where time
  82.     will look like its running backwards 1/18th of a second.  The resolution
  83.     of the clock is 1/(18*256) = 1/4608 second.  66 ticks of this clock
  84.     are supposed to be equal to a monitor 1/70 second tick.}
  85.   ASM
  86.     mov  ah,0                  {get tick count from Dos and use For hi 3 Bytes}
  87.     int  01ah                  {lo order count in DX, hi order in CX}
  88.     mov  ah,dl
  89.     mov  dl,dh
  90.     mov  dh,cl
  91.     mov  al,0                  {read lo Byte straight from timer chip}
  92.     out  CMode,al              {latch count}
  93.     mov  al,1
  94.     out  CMode,al              {set up to read count}
  95.     in   al,CData              {read in lo Byte (and discard)}
  96.     in   al,CData              {hi Byte into al}
  97.     neg  al                    {make it so counting up instead of down}
  98.   END; {GetClock}
  99.  
  100.   PROCEDURE DrawFrame(Buffer : Pointer; Chunks : Word); ASSEMBLER;
  101.   {this is the routine that takes a frame and put it on the screen}
  102.   ASM
  103.     cli                        {disable interrupts}
  104.     push ds
  105.     push es
  106.     lds  si,Buffer             {let DS:SI point at the frame to be drawn}
  107.   @Fli_Loop:                   {main loop that goes through all the chunks in a
  108. frame}
  109.     cmp  Chunks,0              {are there any more chunks to draw?}
  110.     je   @Exit
  111.     dec  Chunks                {decrement Chunks For the chunk to process now}
  112.     mov  ax,[Word ptr ds:si+4] {let AX have the ChunkType}
  113.     add  si,6                  {skip the ChunkHeader}
  114.     cmp  ax,0Bh                {is it a FLI_COLor chunk?}
  115.     je   @Fli_Color
  116.     cmp  ax,0Ch                {is it a FLI_LC chunk?}
  117.     je   @Fli_Lc
  118.     cmp  ax,0Dh                {is it a FLI_BLACK chunk?}
  119.     je   @Fli_Black
  120.     cmp  ax,0Fh                {is it a FLI_BRUN chunk?}
  121.     je   @Fli_Brun
  122.     cmp  ax,10h                {is it a FLI_COPY chunk?}
  123.     je   @Fli_Copy
  124.     jmp  @Fli_Loop             {This command should not be necessary }
  125.   @Fli_Color:
  126.     mov  bx,[Word ptr ds:si]   {number of packets in this chunk (always 1?)}
  127.     add  si,2                  {skip the NumberofPackets}
  128.     mov  al,0                  {start at color 0}
  129.     xor  cx,cx                 {reset CX}
  130.   @Color_Loop:
  131.     or   bx,bx                 {set flags}
  132.     jz   @Fli_Loop             {Exit if no more packages}
  133.     dec  bx                    {decrement NumberofPackages For the package to
  134. process now}
  135.     mov  cl,[Byte ptr ds:si+0] {first Byte in packet tells how many colors to
  136. skip}
  137.     add  al,cl                 {add the skiped colors to the start to get the
  138. new start}
  139.     mov  dx,$3C8               {PEL Address Write Mode Register}
  140.     out  dx,al                 {tell the VGA card what color we start changing}
  141.     inc  dx                    {at the port abow the PEL_A_W_M_R is the PEL
  142. Data Register}
  143.     mov  cl,[Byte ptr ds:si+1] {next Byte in packet tells how many colors to
  144. change}
  145.     or   cl,cl                 {set the flags}
  146.     jnz  @Jump_Over            {if NumberstoChange=0 then NumberstoChange=256}
  147.     inc  ch                    {CH=1 and CL=0 => CX=256}
  148.   @Jump_Over:
  149.     add  al,cl                 {update the color to start at}
  150.     mov  di,cx                 {since each color is made of 3 Bytes (Red, Green
  151. & Blue) we have to -}
  152.     shl  cx,1                  {- multiply CX (the data counter) With 3}
  153.     add  cx,di                 {- CX = old_CX shl 1 + old_CX   (the fastest way
  154. to multiply With 3)}
  155.     add  si,2                  {skip the NumberstoSkip and NumberstoChange
  156. Bytes}
  157.     rep  outsb                 {put the color data to the VGA card FAST!}
  158.     jmp  @Color_Loop           {finish With this packet - jump back}
  159.   @Fli_Lc:
  160.     mov  ax,0A000h
  161.     mov  es,ax                 {let ES point at the screen segment}
  162.     mov  di,[Word ptr ds:si+0] {put LinestoSkip into DI -}
  163.     mov  ax,di                 {- to get the offset address to this line we
  164. have to multiply With 320 -}
  165.     shl  ax,8                  {- DI = old_DI shl 8 + old_DI shl 6 -}
  166.     shl  di,6                  {- it is the same as DI = old_DI*256 + old_DI*64
  167. = old_DI*320 -}
  168.     add  di,ax                 {- but this way is faster than a plain mul}
  169.     mov  bx,[Word ptr ds:si+2] {put LinestoChange into BX}
  170.     add  si,4                  {skip the LinestoSkip and LinestoChange Words}
  171.     xor  cx,cx                 {reset cx}
  172.   @Line_Loop:
  173.     or   bx,bx                 {set flags}
  174.     jz   @Fli_Loop             {Exit if no more lines to change}
  175.     dec  bx
  176.     mov  dl,[Byte ptr ds:si]   {put PacketsInLine into DL}
  177.     inc  si                    {skip the PacketsInLine Byte}
  178.     push di                    {save the offset address of this line}
  179.   @Pack_Loop:
  180.     or   dl,dl                 {set flags}
  181.     jz   @Next_Line            {Exit if no more packets in this line}
  182.     dec  dl
  183.     mov  cl,[Byte ptr ds:si+0] {put BytestoSkip into CL}
  184.     add  di,cx                 {update the offset address}
  185.     mov  cl,[Byte ptr ds:si+1] {put BytesofDatatoCome into CL}
  186.     or   cl,cl                 {set flags}
  187.     jns  @Copy_Bytes           {no SIGN means that CL number of data is to come
  188. -}
  189.                                {- else the next data should be put -CL number
  190. of times}
  191.     mov  al,[Byte ptr ds:si+2] {put the Byte to be Repeated into AL}
  192.     add  si,3                  {skip the packet}
  193.     neg  cl                    {Repeat -CL times}
  194.     rep  stosb
  195.     jmp  @Pack_Loop            {finish With this packet}
  196.   @Copy_Bytes:
  197.     add  si,2                  {skip the two count Bytes at the start of the
  198. packet}
  199.     rep  movsb
  200.     jmp  @Pack_Loop            {finish With this packet}
  201.   @Next_Line:
  202.     pop  di                    {restore the old offset address of the current
  203. line}
  204.     add  di,320                {offset address to the next line}
  205.     jmp  @Line_Loop
  206.   @Fli_Black:
  207.     mov  ax,0A000h
  208.     mov  es,ax                 {let ES:DI point to the start of the screen}
  209.     xor  di,di
  210.     mov  cx,32000              {number of Words in a screen}
  211.     xor  ax,ax                 {color 0 is to be put on the screen}
  212.     rep  stosw
  213.     jmp  @Fli_Loop             {jump back to main loop}
  214.   @Fli_Brun:
  215.     mov  ax,0A000h
  216.     mov  es,ax                 {let ES:DI point at the start of the screen}
  217.     xor  di,di
  218.     mov  bx,200                {numbers of lines in a screen}
  219.     xor  cx,cx
  220.   @Line_Loop2:
  221.     mov  dl,[Byte ptr ds:si]   {put PacketsInLine into DL}
  222.     inc  si                    {skip the PacketsInLine Byte}
  223.     push di                    {save the offset address of this line}
  224.   @Pack_Loop2:
  225.     or   dl,dl                 {set flags}
  226.     jz   @Next_Line2           {Exit if no more packets in this line}
  227.     dec  dl
  228.     mov  cl,[Byte ptr ds:si]   {put BytesofDatatoCome into CL}
  229.     or   cl,cl                 {set flags}
  230.     js   @Copy_Bytes2          {SIGN meens that CL number of data is to come -}
  231.                                {- else the next data should be put -CL number
  232. of times}
  233.     mov  al,[Byte ptr ds:si+1] {put the Byte to be Repeated into AL}
  234.     add  si,2                  {skip the packet}
  235.     rep  stosb
  236.     jmp  @Pack_Loop2           {finish With this packet}
  237.   @Copy_Bytes2:
  238.     inc  si                    {skip the count Byte at the start of the packet}
  239.     neg  cl                    {Repeat -CL times}
  240.     rep  movsb
  241.     jmp  @Pack_Loop2           {finish With this packet}
  242.   @Next_Line2:
  243.     pop  di                    {restore the old offset address of the current
  244. line}
  245.     add  di,320                {offset address to the next line}
  246.     dec  bx                    {any more lines to draw?}
  247.     jnz  @Line_Loop2
  248.     jmp  @Fli_Loop             {jump back to main loop}
  249.   @Fli_Copy:
  250.     mov  ax,0A000h
  251.     mov  es,ax                 {let ES:DI point to the start of the screen}
  252.     xor  di,di
  253.     mov  cx,32000              {number of Words in a screen}
  254.     rep  movsw
  255.     jmp  @Fli_Loop             {jump back to main loop}
  256.   @Exit:
  257.     sti                        {enable interrupts}
  258.     pop  es
  259.     pop  ds
  260.   END; {DrawFrame}
  261.  
  262.   CONSTRUCTOR TFliPlayer.Init;
  263.   BEGIN
  264.     IF MemAvail < BufSize THEN Fail;
  265.     GetMem(Buffer,BufSize);
  266.     ClearSpeed;
  267.   END; {Init}
  268.  
  269.   DESTRUCTOR TFliPlayer.Done;
  270.   BEGIN
  271.     FreeMem(Buffer,BufSize);
  272.   END; {Done}
  273.  
  274.   PROCEDURE TFliPlayer.SetSpeed(Speed : Integer);
  275.   BEGIN
  276.     Interval := Speed * Clock_Scale;
  277.   END; {SetSpeed}
  278.  
  279.   PROCEDURE TFliPlayer.ClearSpeed;
  280.   BEGIN
  281.     Interval := -1;
  282.   END; {ClearSpeed}
  283.  
  284.   PROCEDURE TFliPlayer.Play(Filename : String);
  285.   VAR
  286.     MainHeader  : MainHeaderRec;
  287.     FrameHeader : FrameHeaderRec;
  288.     FrameSize   : LongInt;
  289.     RestartPos  : LongInt;
  290.     Frame       : Word;
  291.     Timeout     : LongInt;
  292.  
  293.     FUNCTION ReadHeader : Boolean;
  294.     BEGIN
  295.       BlockRead(FliFile,MainHeader,SizeOf(MainHeader)); {Read header record}
  296.       WITH MainHeader DO
  297.         IF ID <> $AF11 THEN
  298.           ReadHeader := FALSE {Not a .FLI File}
  299.         ELSE
  300.           BEGIN
  301.             IF Interval = -1 THEN {Read speed from header}
  302.               Interval := Speed * Clock_Scale;
  303.             ReadHeader := TRUE;
  304.           END;
  305.     END; {ReadHeader}
  306.  
  307.     PROCEDURE ReadFrame;
  308.     BEGIN
  309.       BlockRead(FliFile,FrameHeader,SizeOf(FrameHeader));
  310.       FrameSize := FrameHeader.Size - SizeOf(FrameHeader);
  311.     END; {ReadFrame}
  312.  
  313.     PROCEDURE ProcessFrame;
  314.     BEGIN
  315.       BlockRead(FliFile,Buffer^,FrameSize);
  316.       DrawFrame(Buffer,FrameHeader.Chunks);
  317.     END; {ProcessFrame}
  318.  
  319.   BEGIN {Play}
  320.     {$I-}
  321.     Assign(FLiFile,Filename);
  322.     Reset(FliFile,1);
  323.     IF (IOResult = 0) THEN
  324.       BEGIN
  325.         IF ReadHeader THEN
  326.           BEGIN
  327.             VideoMode(MCGA);
  328.             InitClock;
  329.             ReadFrame;
  330.             RestartPos := SizeOf(MainHeader) + SizeOf(FrameHeader) + FrameSize;
  331.             ProcessFrame;
  332.             REPEAT
  333.               Frame := 1;
  334.               REPEAT
  335.                 Timeout := GetClock + Interval;
  336.                 ReadFrame;
  337.                 IF FrameSize <> 0 THEN
  338.                   ProcessFrame;
  339.                 REPEAT UNTIL GetClock > Timeout;
  340.                 Inc(Frame);
  341.               UNTIL (Frame > MainHeader.Frames) OR Keypressed;
  342.               Seek(FliFile,RestartPos);
  343.             UNTIL Keypressed;
  344.             VideoMode(CO80);
  345.           END;
  346.         Close(FliFile);
  347.       END;
  348.     {$I+}
  349.   END; {Play}
  350.  
  351. {---------------------------------------------------------------------------}
  352.  
  353.   FUNCTION Is286Able: Boolean; ASSEMBLER;
  354.   ASM
  355.     PUSHF
  356.     POP     BX
  357.     AND     BX,0FFFH
  358.     PUSH    BX
  359.     POPF
  360.     PUSHF
  361.     POP     BX
  362.     AND     BX,0F000H
  363.     CMP     BX,0F000H
  364.     MOV     AX,0
  365.     JZ      @@1
  366.     MOV     AX,1
  367.   @@1:
  368.   END; {Is286Able}
  369.  
  370.   FUNCTION IsVGA : Boolean; ASSEMBLER;
  371.   ASM
  372.     MOV  AX,1A00h
  373.     MOV  BL,10h
  374.     INT  10h
  375.     CMP  BL,8
  376.     MOV  AX,1
  377.     JZ   @@1
  378.     MOV  AX,0
  379.   @@1:
  380.   END; {IsVGA}
  381.  
  382.   PROCEDURE AAPlay(Filename : String);
  383.   VAR
  384.     Player : TFliPlayer;
  385.   BEGIN
  386.     IF Is286Able AND IsVga THEN
  387.       WITH Player DO
  388.         IF Init THEN
  389.           BEGIN
  390.             Play(Filename);
  391.             Done;
  392.           END;
  393.   END; {AAPlay}
  394.  
  395. {===========================================================================}
  396.  
  397. END.
  398.